﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NMF.Optimizations.Optimizer
{
    public class BruteForceOptimizer : OptimizerBase, IOptimizer
    {
        private static BruteForceOptimizer bruteForceOptimizer;

        public static BruteForceOptimizer Instance
        {
            get
            {
                if (bruteForceOptimizer == null) bruteForceOptimizer = new BruteForceOptimizer();
                return bruteForceOptimizer;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")]
        protected override IOptimizationScenario FindBestScenario(IOptimizationScenario initialScenario, IScenarioEvaluator evaluator)
        {
            var bestScenario = initialScenario;
            FillAlternatives(initialScenario, initialScenario.Optimization, evaluator, ref bestScenario);
            return bestScenario;
        }

        private void FillAlternatives(IOptimizationScenario currentScenario, Optimization optimization, IScenarioEvaluator evaluator, ref IOptimizationScenario bestScenario)
        {
            var mods = optimization.GetCurrentModifications().Distinct().ToArray();
            if (!optimization.ForceModifications || mods.Length == 0)
            {
                currentScenario.Cost = evaluator.EvaluateScenario(currentScenario);
                if (currentScenario.Cost < bestScenario.Cost)
                {
                    bestScenario = currentScenario;
                }
            }
            foreach (var mod in mods)
            {
                if (!mod.Apply()) continue;
                var scenario = currentScenario.Fork(mod);
                FillAlternatives(scenario, optimization, evaluator, ref bestScenario);
                mod.Reverse();
            }
        }
    }
}
